
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       fal_flash_sim_port.c
  * @author     baiyang
  * @date       2022-9-29
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include <stdint.h>
#include <string.h>
#include <rtthread.h>

#if defined(RT_USING_FAL)
#include <fal.h>
#endif

#include <rtdbg.h>
/*-----------------------------------macro------------------------------------*/
#define LOG_TAG                "drv.flash"

#define SIM_FLASH_BUFF_SIZE (1024*1024*2)
/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/
static int sim_flash_init(void);
static int sim_flash_read(long offset, uint8_t *buf, size_t size);
static int sim_flash_write(long offset, const uint8_t *buf, size_t size);
static int sim_flash_erase(long offset, size_t size);
/*----------------------------------variable----------------------------------*/
static uint8_t sim_flash_buff[SIM_FLASH_BUFF_SIZE];

const struct fal_flash_dev sim_flash =
{
    .name       = "sim_flash",
    .addr       = (uint32_t)&sim_flash_buff[0],
    .len        = SIM_FLASH_BUFF_SIZE,
    .blk_size   = 1*1024,
    .ops        = {sim_flash_init, sim_flash_read, sim_flash_write, sim_flash_erase},
    .write_gran = 8
};
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
static int sim_flash_init(void)
{
    return 1;
}

/**
 * Read data from flash.
 * @note This operation's units is word.
 *
 * @param addr flash address
 * @param buf buffer to store read data
 * @param size read bytes size
 *
 * @return result
 */
static int sim_flash_read(long offset, uint8_t *buf, size_t size)
{
    if(size < 0 || offset >= SIM_FLASH_BUFF_SIZE) {
        LOG_E("read outrange flash size!");
        return -1;
    }

    if(size == 0) {
        return 0;
    }

    int i;
    uint8_t *b = (uint8_t *)buf;
    for (i=0; i<SIM_FLASH_BUFF_SIZE; i++) {
        if (offset+i >= SIM_FLASH_BUFF_SIZE)
        {
            return i;
        }
        
        b[i] = sim_flash_buff[offset+i];
        size--;
        if (size == 0) {
            break;
        }
    }

    return i;
}

/**
 * Write data to flash.
 * @note This operation's units is word.
 * @note This operation must after erase. @see flash_erase.
 *
 * @param addr flash address
 * @param buf the write data buffer
 * @param size write bytes size
 *
 * @return result
 */
static int sim_flash_write(long offset, const uint8_t *buf, size_t size)
{
    if (size < 1) {
        return -RT_EINVAL;
    }

    if(offset + size > SIM_FLASH_BUFF_SIZE) {
        LOG_E("write outrange flash size!");
        return -RT_EINVAL;
    }

    int i;
    const uint8_t *b = (const uint8_t *)buf;
    for (i=0; i<SIM_FLASH_BUFF_SIZE; i++) {
        if (offset+i >= SIM_FLASH_BUFF_SIZE)
        {
            return i;
        }
        
        sim_flash_buff[offset+i] = b[i];
        size--;
        if (size == 0) {
            break;
        }
    }

    return i;
}

/**
 * Erase data on flash.
 * @note This operation is irreversible.
 * @note This operation's units is different which on many chips.
 *
 * @param addr flash address
 * @param size erase bytes size
 *
 * @return result
 */
static int sim_flash_erase(long offset, size_t size)
{
    if (size < 1) {
        return -RT_EINVAL;
    }

    if(offset + size > SIM_FLASH_BUFF_SIZE) {
        LOG_E("ERROR: erase outrange flash size!\n");
        return -1;
    }

    memset(&sim_flash_buff[offset], 0xff, size);

    return size;
}
/*------------------------------------test------------------------------------*/

